
#include "OgreApp.h"
#include "Terrain.h"

RaySceneQuery *raySceneQuery = 0;
OgreApp *app = 0;

//
// Constructor
//

OgreApp::OgreApp()
{
	mFrameListener = 0;
	mRoot = 0;
	mResourcePath = "";
}

//
// Destructor
//

OgreApp::~OgreApp()
{
	Delete(mFrameListener);
	Delete(mRoot);
	Delete(terrain);
}

//
// Go
//

void OgreApp::go()
{
	if(!setup())
		return;

	mRoot->startRendering();

	// clean up
	destroyScene();
}

//
// Setup
//

bool OgreApp::setup()
{
	String pluginsPath;

#ifdef _DEBUG
	pluginsPath = mResourcePath + "Plugins_d.cfg";
#else
	pluginsPath = mResourcePath + "Plugins.cfg";
#endif

	mRoot = new Root(pluginsPath, 
		mResourcePath + "ogre.cfg", mResourcePath + "Ogre.log");

	setupResources();

	bool carryOn = configure();
	if(!carryOn) return false;

	chooseSceneManager();
	createCamera();
	createViewports();

	// Set default mipmap level (NB some APIs ignore this)
	TextureManager::getSingleton().setDefaultNumMipmaps(5);

	// Create any resource listeners (for loading screens)
	createResourceListener();
	// Load resources
	loadResources();

	// Create the scene
	createScene();

	createFrameListener();

	return true;
}

//
// Configure
//

bool OgreApp::configure()
{
	// Show the configuration dialog and initialise the system
	// You can skip this and use root.restoreConfig() to load configuration
	// settings if you were sure there are valid ones saved in ogre.cfg
	if(mRoot->showConfigDialog())
	{
		// If returned true, user clicked OK so initialise
		// Here we choose to let the system create a default rendering window by passing 'true'
		mWindow = mRoot->initialise(true);
		return true;
	}
	else
	{
		return false;
	}
}

//
// ChooseSceneManager
//

void OgreApp::chooseSceneManager()
{
	// Create the SceneManager, in this case a generic one
	//mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
	mSceneMgr = mRoot->createSceneManager("TerrainSceneManager");
}

//
// CreateCamera
//

void OgreApp::createCamera()
{
	// Create the camera
	mCamera = mSceneMgr->createCamera("PlayerCam");

	// Position it at 500 in Z direction
	mCamera->setPosition(Vector3(128,25,128));
	// Look back along -Z
	mCamera->lookAt(Vector3(0,0,-300));
	mCamera->setNearClipDistance( 1 );
	mCamera->setFarClipDistance( 1000 );
}

//
// CreateFrameListener
//

void OgreApp::createFrameListener()
{
	mFrameListener = new TerrainFrameListener(mWindow, mCamera);
	mRoot->addFrameListener(mFrameListener);
}

//
// CreateScene
//

void OgreApp::createScene()
{
	Plane waterPlane;

	// Set ambient light
	mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

	// Create a light
	Light* l = mSceneMgr->createLight("MainLight");
	// Accept default settings: point light, white diffuse, just set position
	// NB I could attach the light to a SceneNode if I wanted it to move automatically with
	//  other objects, but I don't
	l->setPosition(20,80,50);

	// Fog
	// NB it's VERY important to set this before calling setWorldGeometry 
	// because the vertex program picked will be different
	ColourValue fadeColour(0.93, 0.86, 0.76);
	mSceneMgr->setFog( FOG_LINEAR, fadeColour, .001, 500, 1000);
	mWindow->getViewport(0)->setBackgroundColour(fadeColour);

	std::string terrain_cfg("terrain.cfg");
	//mSceneMgr->setWorldGeometry( terrain_cfg );

	terrain = new Terrain(mSceneMgr->getRootSceneNode());
	terrain->SetDimensions(100, 100);
	terrain->SetNodes(65, 65);
	terrain->Create();

	// Infinite far plane?
	if(mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE))
	{
		mCamera->setFarClipDistance(0);
	}

	// Define the required skyplane
	Plane plane;
	// 5000 world units from the camera
	plane.d = 5000;
	// Above the camera, facing down
	plane.normal = -Vector3::UNIT_Y;

	// Set a nice viewpoint
	mCamera->setPosition(707,2500,528);
	mCamera->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329));
	//mRoot->showDebugOverlay( true );

	raySceneQuery = mSceneMgr->createRayQuery(
		Ray(mCamera->getPosition(), Vector3::NEGATIVE_UNIT_Y));
}

//
// DestroyScene
//

void OgreApp::destroyScene() 
{
	Delete(raySceneQuery);
}

//
// CreateViewPorts
//

void OgreApp::createViewports()
{
	// Create one viewport, entire window
	Viewport* vp = mWindow->addViewport(mCamera);
	vp->setBackgroundColour(ColourValue(0,0,0));

	// Alter the camera aspect ratio to match the viewport
	mCamera->setAspectRatio(
		Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}

//
// SetupResources
//

void OgreApp::setupResources()
{
	// Load resource paths from config file
	ConfigFile cf;
	cf.load(mResourcePath + "resources.cfg");

	// Go through all sections & settings in the file
	ConfigFile::SectionIterator seci = cf.getSectionIterator();

	String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		ConfigFile::SettingsMultiMap *settings = seci.getNext();
		ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}
}

//
// CreateResourceListener
//

void OgreApp::createResourceListener()
{

}

//
// LoadResources
//

void OgreApp::loadResources()
{
	// Initialise, parse scripts etc
	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

}